# from ims.sti.models import *
from django.shortcuts import render_to_response, get_object_or_404
from django.http import Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.conf import settings
from couchdbkit import *
import re, difflib,copy

SEARCH_LIMIT = 100

server=client.Server(settings.COUCHDB_HOST)
db = server[settings.COUCHDB_DATABASE_NAME]

def home(request):
	return render_to_response('home.html', {'title': 'Welcome'})


def topic(request, topicName):
	def getReferences(topic,ref_type):
		def deep_find_book_topic(topic_id,head,container):
			if topic_id in head['topics']:
				container.append(head['page'])
			for child in head['children']:
				deep_find_book_topic(topic_id,child,container)
			
		topic_id = topic['id']
		if ref_type=='book':
			books = [row['value'] for row in db.view('sti/books').all()]
			references = []
			for book in books:
				pages = []
				for chap in book['toc']:
					deep_find_book_topic(topic_id,chap,pages)
				if len(pages) >0:
					pages = [p for p in pages if p]
					references.append((book,pages))
					
		if ref_type=='lecture':
			courses = [row['value'] for row in db.view('sti/courses').all()]			
			references = []
			for course in courses:
				ref = []
				for lec in course['lectures']:
					if topic_id in lec['topics']:
						ref.append(lec)
				if len(ref)>0:
					references.append((course,ref))
		return references
	
	def getChildren(init_topic):
		children={}
		for cat in init_topic['categories']:
			assoc_topics =set([a['target'] for a in cat['associations'] if a['type']=='parent to child'])
			if len(assoc_topics)>0:
				children[cat['category']]=assoc_topics
		results = {}
		for cat in children:
			results[cat]=[db.view('sti/topics',key=t).first() for t in children[cat]]
			results[cat]=[t['value'] for t in results[cat] if t]
		return results

	def getParents(init_topic,all_topics):
		parents={}
		for index,t in enumerate(all_topics):
			if t['_id']==init_topic['_id']:
				continue
			for cat in t['categories']:
				category = cat['category']
				if category not in parents:
					parents[category]=set([])
				for assoc in cat['associations']:
					if init_topic['_id']==assoc['target'] and assoc['type']=="parent to child":
						parents[category] |= set([index])
		results = {}
		for cat in parents:
			results[cat]=[all_topics[index] for index in sorted(parents[cat])]
		return results	
	
	def getRelated(init_topic,all_topics):
		result = set([])
		stack = set([(init_topic['_id'],None)])
		while len(stack) > 0:
			topic_id,category = stack.pop()
			result |= set([(topic_id,category)])
			topic = db.view('sti/topics',key=topic_id).first()['value']
			for cat in topic['categories']:
				for assoc in cat['associations']:
					if assoc['type']=='related':
						stack |= set([(assoc['target'],cat['category'])]).difference(result)
		related={}
		for t in result:
			if t[0]==init_topic['_id']:
				continue
			if t[1] not in related:
				related[t[1]]=set([])
			related[t[1]] |= set([t[0]])
		results = {}
		for cat in related:
			results[cat]=[db.view('sti/topics',key=t).first() for t in related[cat]]
			results[cat]=[t['value'] for t in results[cat] if t]
		return results
	
	def getPractioners(topic,persons):
		results=[]
		for person in persons:
			for knowledge in person['knowledge']:
				if knowledge['topic']==topic['_id']:
					results.append(person)
		return results
	
	def getSource(topic,source_type):
		results={}
		for cat in topic['categories']:
			category = cat['category']
			if not category in results:
				results[category] = []
			for source in cat['sources']:
				if source['type']==source_type:
					results[category].append(source)
		return results
			

		
	try:
		topic=db.get("topics/"+topicName)
	except client.ResourceNotFound:
		raise Http404
	all_topics = [row['value'] for row in db.view('sti/topics').all()]	
	all_persons = [row['value'] for row in db.view('sti/persons').all()]
	
	source_choices = ['MathWorld','PlanetMath','Wikipedia','ISI']
	
	children =getChildren(topic)
	parents = getParents(topic,all_topics)
	related	 =getRelated(topic,all_topics)
	isi_url = getSource(topic,source_choices[3])
	aux_encyclopedia_urls = [getSource(topic,source_type) for source_type in source_choices[:3]]
	data={}
	for category in children:
		if not category in data:
			data[category]={'name':category,}
		data[category]['children']=children[category]
	for category in parents:
		if not category in data:
			data[category]={'name':category,}
		data[category]['parents']=parents[category] 
	for category in related:
		if not category in data:
			data[category]={'name':category,}
		data[category]['related']=related[category]
	for category in isi_url:
		if not category in data:
			data[category]={'name':category,}
		data[category]['isi_url']=isi_url[category]
	
	for url_type in aux_encyclopedia_urls:
		for category in url_type:
			if not category in data:
				data[category]={'name':category,}
			if not 'aux_encyclopedia_urls' in data[category]:
				data[category]['aux_encyclopedia_urls']=[]
			data[category]['aux_encyclopedia_urls']+=url_type[category]
	
	context = {
		'topic': topic,
		'title': topic['name'],
		'data': [data[category] for category in data],
		'references_book': getReferences(topic,'book'),
		'references_lecture': getReferences(topic,'lecture'),		}
	return render_to_response('topic.html',context)


def topicIndex(request):
	page = request.GET.get('page', 'A')
	topics = [row['value'] for row in db.view('sti/topics',startkey='topics/'+page,endkey='topics/'+chr(ord(page)+1)).all()]
	context = {
		"topics": topics,
		"current_letter": page,
		"title": "Topic Index"}
	return render_to_response('topicIndex.html', context)

def search(request):
	query = request.GET['q'].lower()

	exactMatch = db.view('sti/topics',key=query).first()
	if exactMatch:
		return HttpResponseRedirect('/'+exactMatch['id'])
		
		
	topic_names = [row['key'] for row in db.view('sti/topics').all() if 'topics/' not in row['key']]	
	approxMatches = difflib.get_close_matches(query.lower(),topic_names)
	if not approxMatches:
		approxMatches = [t for t in topic_names if query in t]
		
	if approxMatches:
		context = {'matches': [db.view('sti/topics',key=m).first()['value'] for m in approxMatches]}
		return render_to_response('searchResults.html', context)	
			
	return render_to_response('noResults.html')

def personIndex(request):
	persons = [row['value'] for row in db.view('sti/persons').all()]
	data = []
	for person in persons:
		# topics = [db.get(k['topic']) for k in person['knowledge']]
		# data.append((person['first_name'],person['last_name'],topics))
		topics = [db.view('sti/topics',key=k['topic']).first() for k in person['knowledge']]
		topics = [t['value']  for t in topics if t]
		data.append((person['first_name'],person['last_name'],topics))
	context = {'title': 'Person Index',
				'data': data,
				}
	return render_to_response('personIndex.html', context)


def courseIndex(request):
	context = {
		"courses": [row['value'] for row in db.view('sti/courses').all()],
		"title": "Course Index"}
	return render_to_response('courseIndex.html', context)



def course(request,courseName,choice='lecture'):
	try:
		course=db.get("courses/"+courseName)
	except ResourceNotFound:
		raise Http404
	
	def availability(course):
		l_flag = b_flag = False
		if course['lectures']: l_flag=True
		if course['books']: b_flag = True
		
		if l_flag and b_flag: return 'both'
		elif l_flag: return 'lecture'
		elif b_flag: return 'book'
		else: return 'none'
	
	semester = "[%s]" % course['semester']	if course['semester'] else ""
	name = course['name'] if  course['name'] else ""
	description = "-- "+course['description'] if course['description'] else ""
	books=[db.view('sti/books',key=bk).first() for bk in course['books']]
	books=[bk['value'] for bk in books if bk]
	course=copy.deepcopy(course)
	for lecture in course['lectures']:
		lecture['topics']=[db.view('sti/topics',key=t).first() for t in lecture['topics']]
		lecture['topics']=[t['value']  for t in lecture['topics'] if t]
		
	context = {
		'choice' : choice,
		'availability' : availability(course),
		'course' : course,
		'title' : ' '.join([semester,name,description]),
		'books' : [generate_book_data(bk) for bk in books]
		}
	return render_to_response('course.html',context)


def bookIndex(request):
	def getName(s):
		if len(s) == 0:
			return ""
		else:
			return s.split('/')[-1]
	books = [row['value'] for row in db.view('sti/books').all()]
	data = [(bk, [getName(a) for a in bk['authors']],getName(bk['publisher']) ) for bk in books ]
	context = {
		"data": data,
		"title": "Book Index",
		}
	return render_to_response('bookIndex.html', context)

def generate_book_data(book):
	def setBookTopics(head):
		head['topics'] = [db.view('sti/topics',key=t).first() for t in head['topics']]
		head['topics'] = [t['value']  for t in head['topics'] if t]
		for c in head['children']:
			setBookTopics(c)
	
	book=copy.deepcopy(book)
	for chap in book['toc']:
		setBookTopics(chap)
	book['authors']=[db.view('sti/persons',key=a).first() for a in book['authors']]
	book['authors']=[a['value'] for a in book['authors'] if a]
	row = db.view('sti/publishers',key=book['publisher']).first()
	book['publisher']= row['value'] if row else None
	return book

def book(request,bookName):
	try:
		book=db.get('books/'+bookName)
	except ResourceNotFound:
		raise Http404
	
	all_courses = [row['value'] for row in db.view('sti/courses').all()]

	context = {
		'book' : generate_book_data(book),
		'title': book['title'],
		'courses' : [c for c in all_courses if book['title'] in c['books']]
		}
	return render_to_response('book.html', context) 

def redirect(request,ext_url):
	return HttpResponseRedirect(ext_url)

def about(request):
	return render_to_response('about.html', {'title': 'About'})

